#include "ai.h"
#include "ai_search.h"
#include "ai_reflex.h"
#include "players.h"
#include <iostream>
#include <sstream>
#include <cmath>



int help_computes::ai_test_fire_nobody( unsigned int x, unsigned int y, unsigned int tx, unsigned int ty, game_state* state )
{
	if ( state->map->get( x, y ) >= 20000 )
		return -1;
	if ( state->map->get( tx, ty ) >= 20000 )
		return -1;
	if ( ( x == tx ) && ( y == ty ) )
		return -1;
	unsigned int d = floor( sqrt( pow( ( float )( ( int )x - ( int )tx ), 2 ) + pow ( ( float )( ( int )y - ( int )ty ), 2 ) ) + 0.5 );
	double dx = abs( (double)tx - (double)x );
	double dy = abs( (double)ty - (double)y );
	if ( dx == 0 )
	{
		dy = 1;
	}
	else if ( dy == 0 )
	{
		dx = 1;
	}
	else
	{
		if ( dx > dy )
		{
			dy = dy / dx;
			dx = 1;
		}
		else
		{
			dx = dx / dy;
			dy = 1;	
		}
	}
	double cx = 0;
	double cy = 0;
	unsigned int fx = x;
	unsigned int fy = y;
	int px;
	int py;
	if ( fx > tx )
		px = -1;
	else
		px = 1;
	if ( fy > ty )
		py = -1;
	else
		py = 1;
	bool move = false;
	unsigned int test_d = 0;
	while ( !( fx == tx && fy == ty ) )
	{
		if ( test_d >= mapa::get_instance()->get_size_x() + mapa::get_instance()->get_size_y() )
			return -1;
		if ( state->map->get( fx, fy ) > 20000 )
			return -1;
		if( !move )
		{
			cx += dx;
			cy += dy;
		}
		move = false;
		if ( greater( cx, 0.5 ) )
		{
			--cx;
			fx += px;
			++test_d;
			move = true;
		}
		else if ( greater( cy, 0.5 ) )
		{
			--cy;
			fy += py;
			++test_d;
			move = true;
		}
	}
	return d;
};



int help_computes::ai_test_move_nobody( unsigned int sx, unsigned int sy, unsigned int dx, unsigned int dy, game_state* state )
{
	if ( state->map->get( dx, dy ) >= 20000 )
		return -1;
	if ( state->map->get( sx, sy ) >= 20000 )
		return -1;
	array2d< unsigned int > dist( mapa::get_instance()->get_size_x(), mapa::get_instance()->get_size_y() );
	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for ( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			dist.set( 30000, i, j );
	dist.set( 0, sx, sy );
	std::queue< std::pair< unsigned int, unsigned int > > fronta;
	fronta.push( std::make_pair< unsigned int, unsigned int >( sx, sy ) );
	unsigned int x;
	unsigned int y;	
	while ( !fronta.empty() )
	{
		x = fronta.front().first;
		y = fronta.front().second;
		fronta.pop();
		if ( ( x > 0 ) && ( state->map->get( x - 1, y ) <= 100 ) )
		{
			if ( dist.get( x - 1, y ) > dist.get( x, y ) + state->map->get( x - 1, y ) )
			{
				dist.set( dist.get( x, y ) + state->map->get( x - 1, y ), x - 1, y );
				fronta.push( std::make_pair< unsigned int, unsigned int >( x - 1, y ) );
			}		
		}
		if ( ( x < mapa::get_instance()->get_size_x() - 1 ) && ( state->map->get( x + 1, y ) <= 100 ) )
		{
			if ( dist.get( x + 1, y ) > dist.get( x, y ) + state->map->get( x + 1, y ) )
			{
				dist.set( dist.get( x, y ) + state->map->get( x + 1, y ), x + 1, y );
				fronta.push( std::make_pair< unsigned int, unsigned int >( x + 1, y ) );
			}
		}
		if ( ( y > 0 ) && ( state->map->get( x, y - 1 ) <= 100 ) )
		{
			if ( dist.get( x, y - 1 ) > dist.get( x, y ) + state->map->get( x, y - 1 ) )
			{
				dist.set( dist.get( x, y ) + state->map->get( x, y - 1 ), x, y - 1 );
				fronta.push( std::make_pair< unsigned int, unsigned int >( x, y - 1 ) );
			}
		}
		if ( ( y < mapa::get_instance()->get_size_y() - 1 ) && ( state->map->get( x, y + 1 ) <= 100 ) )
		{
			if ( dist.get( x, y + 1 ) > dist.get( x, y ) + state->map->get( x, y + 1 ) )
			{
				dist.set( dist.get( x, y ) + state->map->get( x, y + 1 ), x, y + 1 );
				fronta.push( std::make_pair< unsigned int, unsigned int >( x, y + 1 ) );
			}
		}
	}
	if ( dist.get( dx, dy ) == 30000 )
		return -1;
	else
		return dist.get( dx, dy );
};



int help_computes::ai_test_fire( unsigned int x, unsigned int y, unsigned int tx, unsigned int ty, game_state* state )
{
	if ( state->map->get( x, y ) >= 20000 )
		return -1;
	if ( state->map->get( tx, ty ) >= 20000 )
		return -1;
	if ( ( x == tx ) && ( y == ty ) )
		return -1;
	unsigned int d = floor( sqrt( pow( ( float )( ( int )x - ( int )tx ), 2 ) + pow ( ( float )( ( int )y - ( int )ty ), 2 ) ) + 0.5 );
	double dx = abs( ( double )tx - ( double )x );
	double dy = abs( ( double )ty - ( double )y );
	if ( dx == 0 )
	{
		dy = 1;
	}
	else if ( dy == 0 )
	{
		dx = 1;
	}
	else
	{
		if(dx > dy)
		{
			dy = dy / dx;
			dx = 1;
		}
		else
		{
			dx = dx / dy;
			dy = 1;	
		}
	}
	double cx = 0;
	double cy = 0;
	unsigned int fx = x;
	unsigned int fy = y;
	int px;
	int py;
	if ( fx > tx )
		px = -1;
	else
		px = 1;
	if( fy > ty )
		py = -1;
	else
		py = 1;
	bool move = false;
	unsigned int test_d = 0;
	while ( !( fx == tx && fy == ty ) )
	{
		if ( test_d >= mapa::get_instance()->get_size_x() + mapa::get_instance()->get_size_y() )
			return -1;
		if ( ( state->map->get( fx, fy ) > 20000 ) )
			return -1;
		if ( ( ( dynamic_cast< unit* >( state->objects->get( fx, fy ) ) != 0 ) && ( ( ( fx != tx ) || ( fy != ty ) ) && ( ( fx != x ) || ( fy != y ) ) ) ) )
			return -1;
		if( !move )
		{
			cx += dx;
			cy += dy;
		}
		move = false;
		if ( greater( cx, 0.5 ) )
		{
			--cx;
			fx += px;
			++test_d;
			move = true;
		}
		else if ( greater( cy, 0.5 ) )
		{
			--cy;
			fy += py;
			++test_d;
			move = true;
		}
	}
	return d;
}



int help_computes::ai_test_move( unsigned int sx, unsigned int sy, unsigned int dx, int unsigned dy, game_state* state )
{
	if ( ( state->map->get( dx, dy ) >= 20000 ) || ( ( dynamic_cast< unit* >( state->objects->get( dx, dy ) ) ) != 0 ) )
		return -1;
	if ( state->map->get( sx, sy ) >= 20000 )
		return -1;
	array2d< unsigned int > dist( mapa::get_instance()->get_size_x(), mapa::get_instance()->get_size_y() );
	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for ( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			dist.set( 30000, i, j );
	dist.set( 0, sx, sy );
	std::queue< std::pair< unsigned int, unsigned int > > fronta;
	fronta.push( std::make_pair< unsigned int, unsigned int >( sx, sy ) );
	unsigned int x;
	unsigned int y;	
	while ( !fronta.empty() )
	{
		x = fronta.front().first;
		y = fronta.front().second;
		fronta.pop();
		if ( ( x > 0 ) && ( state->map->get( x - 1, y ) <= 100 ) && ( ( dynamic_cast< unit* >( state->objects->get( x - 1, y ) ) ) == 0 ) )
		{
			if ( dist.get( x - 1, y ) > dist.get( x, y ) + state->map->get( x - 1, y ) )
			{
				dist.set( dist.get( x, y ) + state->map->get( x - 1, y ), x - 1, y );
				fronta.push( std::make_pair< unsigned int, unsigned int >( x - 1, y ) );
			}		
		}
		if ( ( x < mapa::get_instance()->get_size_x() - 1 ) && ( state->map->get( x + 1, y ) <= 100 ) && ( ( dynamic_cast< unit* >( state->objects->get( x + 1, y ) ) ) == 0 ) )
		{
			if ( dist.get( x + 1, y ) > dist.get( x, y ) + state->map->get( x + 1, y ) )
			{
				dist.set( dist.get( x, y ) + state->map->get( x + 1, y ), x + 1, y );
				fronta.push( std::make_pair< unsigned int, unsigned int >( x + 1, y ) );
			}
		}
		if ( ( y > 0 ) && ( state->map->get( x, y - 1 ) <= 100 ) && ( ( dynamic_cast< unit* >( state->objects->get( x, y - 1 ) ) ) == 0 ) )
		{
			if ( dist.get( x, y - 1 ) > dist.get( x, y ) + state->map->get( x, y - 1 ) )
			{
				dist.set( dist.get( x, y ) + state->map->get( x, y - 1 ), x, y - 1 );
				fronta.push( std::make_pair< unsigned int, unsigned int >( x, y - 1 ) );
			}
		}
		if ( ( y < mapa::get_instance()->get_size_y() - 1 ) && ( state->map->get( x, y + 1 ) <= 100 ) && ( ( dynamic_cast< unit* >( state->objects->get( x, y + 1 ) ) ) == 0 ) )
		{
			if ( dist.get( x, y + 1 ) > dist.get( x, y ) + state->map->get( x, y + 1 ) )
			{
				dist.set( dist.get( x, y ) + state->map->get( x, y + 1 ), x, y + 1 );
				fronta.push( std::make_pair< unsigned int, unsigned int >( x, y + 1 ) );
			}
		}
	}
	if ( dist.get( dx, dy ) == 30000 )
		return -1;
	else
		return dist.get( dx, dy );
};



bool help_computes::ai_move( unit* u, unsigned int x, unsigned int y, game_state* state )
{
	int d = ai_test_move( u->get_x(), u->get_y(), x, y, state ) / 10;
	if ( ( d != -1 ) && ( ( d * ( ( int )u->get_cost_move() ) ) <= u->get_player()->get_time() ) )
	{	
		u->get_player()->set_time( u->get_player()->get_time() - ( d * ( int )u->get_cost_move() ) );
		bonus* b = dynamic_cast< bonus* >( state->objects->get( x, y ) );
		if ( b!= 0 )
		{
			b->effect( u );
		}
		state->objects->set( 0, u->get_x(), u->get_y() );
		u->set_pos( x, y );
		state->objects->set( u, x, y );
		return true;
	}
	else
	{
		return false;
	}
};



bool help_computes::ai_fire( unit* u, unsigned int x, unsigned int y, game_state* state )
{
	if ( ( ai_test_fire( u->get_x(), u->get_y(), x, y, state ) <= ( int )u->get_range() ) && ( ( int )u->get_cost_fire() <= u->get_player()->get_time() ) )
	{
		unit* tu = dynamic_cast< unit* >( state->objects->get( x, y ) );
		if ( tu != 0 )
		{
			if ( u->get_player() == tu->get_player() )
				return false;
			u->get_player()->set_time( u->get_player()->get_time() - ( int )u->get_cost_fire() );
			int x = ( int )u->get_weapon() - ( int )tu->get_shield();
			if ( x > 0 )
				tu->set_health( tu->get_health() - x );
			else
				tu->set_health( tu->get_health() - 1 );
			if ( tu->get_health() <= 0 )
			{
				player* tup = tu->get_player();
				state->objects->set( 0, tu->get_x(), tu->get_y() );
				for ( vector< unit* >::iterator it = tu->get_player()->units.begin(); it != tu->get_player()->units.end(); ++it )
				{
					if ( *it == tu )
					{
						tu->get_player()->units.erase( it );
						break;
					}
				}
				delete tu;
				if ( tup->units.empty() )
					tup->set_out();
			}
			return true;
		}
		else
		{
			return false;
		}

	}
	else
	{
		return false;
	}
};



void help_computes::ai_next_turn( game_state* state )
{
	unsigned int current_player_id = state->current_player_id;
	for ( unsigned int i = 0; i < state->players_count; ++i )
	{
		++current_player_id;
		current_player_id = current_player_id % state->players_count;
		if ( state->plrs[ current_player_id ]->is_in_game() )
			break;
	}
	state->current_player_id = current_player_id;
	state->plrs[ current_player_id ]->set_time( parameters::get_instance()->game_parameters[ "START_TIME" ] );
};



bool help_computes::apply_command( game_state* state, std::string cmd )
{
	std::istringstream sstr( cmd );
	string c;
	unsigned int x;
	unsigned int y;
	unsigned int u;
	sstr >> c;

	if ( sstr.fail() )
	{
		return false;
	}
	else if ( c == "ATT" )
	{
		sstr >> u;
		sstr >> x;
		sstr >> y;
		if ( help_computes::ai_fire( state->plrs[ state->current_player_id ]->units[ u ], x, y, state ) )
			return true;
		else
			return false;
	}
	else if ( c == "MOV" )
	{
		sstr >> u;
		sstr >> x;
		sstr >> y;
		if ( help_computes::ai_move( state->plrs[ state->current_player_id ]->units[ u ], x, y, state ) )
			return true;
		else
			return false;
	}
	else if ( c == "NXT" )
	{
		help_computes::ai_next_turn( state );
		return true;
	}
	else
		return false;
};



array2d< unsigned int >* help_computes::map_places_estimate( game_state* state )
{
	array2d< unsigned int >* estimated_places = new array2d< unsigned int >( mapa::get_instance()->get_size_x(), mapa::get_instance()->get_size_y() );

	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for ( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			estimated_places->set( 0, i, j );

	for ( unsigned int x = 0; x < mapa::get_instance()->get_size_x(); ++x )
		for ( unsigned int y = 0; y < mapa::get_instance()->get_size_y(); ++y )
		{
			if ( state->map->get( x, y ) >= 20000 )
				continue;		
			if ( state->reachable_places->get( x, y ) == false )
				continue;
			for ( unsigned int tx = 0; tx < mapa::get_instance()->get_size_x(); ++tx )
				for ( unsigned int ty = 0; ty < mapa::get_instance()->get_size_y(); ++ty )
				{
					if ( state->map->get( tx, ty ) >= 20000 )
						continue;
					int d = ai_test_fire_nobody( x, y, tx, ty, state);
					if ( ( d != -1 ) && ( d <= parameters::get_instance()->ai_parameters[ "GENERAL" ][ "test_range" ] ) )
					{
						estimated_places->set( estimated_places->get( tx, ty ) + 1, tx, ty );
					}
				}
		}

	return estimated_places;
};



array2d< bool >* help_computes::map_places_reachable( game_state* state )
{
	array2d< bool >* reachable_places = new array2d< bool >( mapa::get_instance()->get_size_x(), mapa::get_instance()->get_size_y() );
	std::queue< std::pair< unsigned int, unsigned int > > fronta;

	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for ( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			reachable_places->set( false, i, j );

	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for ( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			if ( ( state->map->get( i, j ) % 10 ) != 0 )
				fronta.push( std::make_pair< unsigned int, unsigned int >( i, j ) );

	unsigned int x;
	unsigned int y;	

	while ( !fronta.empty() )
	{
		x = fronta.front().first;
		y = fronta.front().second;
		fronta.pop();
		if ( reachable_places->get( x, y ) == false )
		{
			reachable_places->set( true, x, y );
			if ( ( x > 0 ) && ( state->map->get( x - 1, y ) <= 100 ) && ( reachable_places->get( x - 1, y ) == false ) )
				fronta.push( std::make_pair< unsigned int, unsigned int >( x-1, y ) );	
			if ( ( x < mapa::get_instance()->get_size_x() - 1 ) && ( state->map->get( x + 1, y ) <= 100 ) && ( reachable_places->get( x + 1, y ) == false ) )
				fronta.push( std::make_pair< unsigned int, unsigned int >( x + 1, y ) );
			if ( (y > 0 ) && ( state->map->get( x, y - 1 ) <= 100 ) && ( reachable_places->get( x, y - 1 ) == false ) )
				fronta.push( std::make_pair< unsigned int, unsigned int >( x, y - 1 ) );
			if ( ( y < mapa::get_instance()->get_size_y() - 1 ) && ( state->map->get( x, y + 1 ) <= 100 ) && ( reachable_places->get( x, y + 1 ) == false ) )
				fronta.push( std::make_pair< unsigned int, unsigned int >( x, y + 1 ) );
		}
	}

	return reachable_places;
};



array2d< unsigned int >* help_computes::map_places_dangerous( game_state *state )
{
	array2d< unsigned int >* dangerous_places = new array2d< unsigned int >( mapa::get_instance()->get_size_x(), mapa::get_instance()->get_size_y() );;

	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			dangerous_places->set( 0, i, j );

	for ( unsigned int cpl = 0; cpl < state->players_count; ++cpl )
	{
		if ( state->plrs[ cpl ]->get_id() == state->current_player_id )
			continue;
		for ( unsigned int cun = 0; cun < state->plrs[ cpl ]->units.size(); ++cun )
			for ( unsigned int tx = 0; tx < mapa::get_instance()->get_size_x(); ++tx )
				for ( unsigned int ty = 0; ty < mapa::get_instance()->get_size_y(); ++ty )
				{
					if ( state->map->get( tx, ty ) >= 20000 )
						continue;
					int d = ai_test_fire( state->plrs[ cpl ]->units[ cun ]->get_x(), state->plrs[ cpl ]->units[ cun ]->get_y(), tx, ty, state );
					if ( ( d != -1 ) && ( d <= ( int )state->plrs[ cpl ]->units[ cun ]->get_range() ) )
						dangerous_places->set( dangerous_places->get( tx, ty ) + 1, tx, ty );
				}
	}

	return dangerous_places;
};



array2d< unsigned int >* help_computes::map_places_dangerous_nobody( game_state *state )
{
	array2d< unsigned int >* dangerous_places_nobody = new array2d< unsigned int >( mapa::get_instance()->get_size_x(), mapa::get_instance()->get_size_y() );;

	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			dangerous_places_nobody->set( 0, i, j );

	for ( unsigned int cpl = 0; cpl < state->players_count; ++cpl )
	{
		if ( state->plrs[ cpl ]->get_id() == state->current_player_id )
			continue;
		for ( unsigned int cun = 0; cun < state->plrs[ cpl ]->units.size(); ++cun )
			for ( unsigned int tx = 0; tx < mapa::get_instance()->get_size_x(); ++tx )
				for ( unsigned int ty = 0; ty < mapa::get_instance()->get_size_y(); ++ty )
				{
					if ( state->map->get( tx, ty ) >= 20000 )
						continue;
					int d = ai_test_fire_nobody( state->plrs[ cpl ]->units[ cun ]->get_x(), state->plrs[ cpl ]->units[ cun ]->get_y(), tx, ty, state );
					if ( ( d != -1 ) && ( d <= ( int )state->plrs[ cpl ]->units[ cun ]->get_range() ) )
						dangerous_places_nobody->set( dangerous_places_nobody->get( tx, ty ) + 1, tx, ty );
				}
	}

	return dangerous_places_nobody;
};



array2d< unsigned int >* help_computes::map_places_attackable( game_state *state )
{
	array2d< unsigned int >* attackable_places = new array2d< unsigned int >( mapa::get_instance()->get_size_x(), mapa::get_instance()->get_size_y() );

	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			attackable_places->set( 0, i, j );

	for ( unsigned int cpl = 0; cpl < state->players_count; ++cpl )
	{
		if ( state->plrs[ cpl ]->get_id() != state->current_player_id )
			continue;
		for ( unsigned int cun = 0; cun < state->plrs[ cpl ]->units.size(); ++cun )
			for ( unsigned int tx = 0; tx < mapa::get_instance()->get_size_x(); ++tx )
				for ( unsigned int ty = 0; ty < mapa::get_instance()->get_size_y(); ++ty )
				{
					if ( state->map->get( tx, ty ) >= 20000 )
						continue;
					int d = ai_test_fire( state->plrs[ cpl ]->units[ cun ]->get_x(), state->plrs[ cpl ]->units[ cun ]->get_y(), tx, ty, state );
					if ( ( d != -1 ) && ( d <= ( int )state->plrs[ cpl ]->units[ cun ]->get_range() ) )
						attackable_places->set( attackable_places->get( tx, ty ) + 1, tx, ty );
				}
	}

	return attackable_places;
};



double help_computes::game_state_estimate( game_state* state )
{
	parameters* param = parameters::get_instance();
	double health_coef = param->ai_parameters[ "GENERAL" ][ "health_coef" ];
	double weapon_coef = param->ai_parameters[ "GENERAL" ][ "weapon_coef" ];
	double shield_coef = param->ai_parameters[ "GENERAL" ][ "shield_coef" ];
	double range_coef = param->ai_parameters[ "GENERAL" ][ "range_coef" ];
	double cost_move_coef = param->ai_parameters[ "GENERAL" ][ "cost_move_coef" ];
	double cost_fire_coef = param->ai_parameters[ "GENERAL" ][ "cost_fire_coef" ];
	double position_coef = param->ai_parameters[ "GENERAL" ][ "position_coef" ];
	double attack_coef = param->ai_parameters[ "GENERAL" ][ "attack_coef" ];
	double danger_coef = param->ai_parameters[ "GENERAL" ][ "danger_coef" ];

	double score = 0;
	int coef;
	unit* cu;
	
	for ( unsigned int i = 0; i < state->players_count; ++i )
	{
		if ( state->plrs[ i ]->get_id() == state->current_player_id )
			coef = 1;
		else
			coef = -1;
		for ( unsigned int j = 0; j < state->plrs[ i ]->units.size(); ++j )
		{
			cu = state->plrs [ i ]->units[ j ];
			score += ( ( cu->get_health() * health_coef + cu->get_weapon() * weapon_coef + cu->get_shield() * shield_coef + cu->get_range() * range_coef + cu->get_cost_move() * cost_move_coef + cu->get_cost_fire() * cost_fire_coef + state->estimated_places->get( cu->get_x(), cu->get_y() ) * position_coef + state->attackable_places->get( cu->get_x(), cu->get_y() ) * attack_coef + state->dangerous_places->get( cu->get_x(), cu->get_y() ) * danger_coef ) * coef );
		}
	}

	return score;
};



game_state::game_state( unsigned int pl_c, unsigned int c_pl_id, player** pl, array2d< object* >* obj, array2d< unsigned int >* mp, double sc, array2d< unsigned int >* ep, array2d< bool >* rp, array2d< unsigned int >* dp, array2d< unsigned int >* dpn, array2d< unsigned int >* ap )
{
	plrs = new player*[ parameters::get_instance()->game_parameters[ "MAX_PL" ] ];
	score = sc;
	map = mp;
	objects = new array2d< object* >( mapa::get_instance()->get_size_x(), mapa::get_instance()->get_size_y() );
	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for ( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			objects->set( 0, i, j );

	current_player_id = c_pl_id;

	players_count = pl_c;
	for ( unsigned int i = 0; i < pl_c; ++i )
		plrs[ i ] = pl[ i ]->clone();

	for ( unsigned int i = 0; i < players_count; ++i )
		for( unsigned int j = 0; j < plrs[ i ]->units.size(); ++j )
			objects->set( plrs[ i ]->units[ j ], plrs[ i ]->units[ j ]->get_x(), plrs[ i ]->units[ j ]->get_y() );

	for ( unsigned int i = 0; i < mapa::get_instance()->get_size_x(); ++i )
		for ( unsigned int j = 0; j < mapa::get_instance()->get_size_y(); ++j )
			if ( ( obj->get( i, j ) != 0 ) && ( ( dynamic_cast< unit* >( obj->get( i, j ) ) ) == 0 ) )
				objects->set( obj->get( i, j )->clone(), i, j );

	estimated_places = ep;
	reachable_places = rp;
	dangerous_places = dp;
	dangerous_places_nobody = dpn;
	attackable_places = ap;
};



game_state::~game_state()
{
	for( unsigned int i = 0; i < players_count; ++i )
		delete plrs[ i ];
	delete [] plrs;
	delete map;
	delete objects;
	if ( estimated_places != 0 )
		delete estimated_places;
	if ( reachable_places != 0 )
		delete reachable_places;
	if ( dangerous_places != 0 )
		delete dangerous_places;
	if ( dangerous_places_nobody != 0 )
		delete dangerous_places_nobody;
	if ( attackable_places != 0 )
		delete attackable_places;
};



game_state* game_state::clone()
{
	game_state* gs = new game_state( players_count, current_player_id, plrs, objects, new array2d< unsigned int >( *map ), score );
	if ( estimated_places != 0 )
		gs->estimated_places = new array2d< unsigned int >( *estimated_places );
	if ( reachable_places != 0 )
		gs->reachable_places = new array2d< bool >( *reachable_places );
	if ( dangerous_places != 0 )
		gs->dangerous_places = new array2d< unsigned int >( *dangerous_places );
	if ( dangerous_places_nobody != 0 )
		gs->dangerous_places_nobody = new array2d< unsigned int >( *dangerous_places_nobody );
	if ( attackable_places != 0 )
		gs->attackable_places = new array2d< unsigned int >( *attackable_places );
	return gs;
};



void algorithm::init( player* p )
{
	owner = p;
	connect( this, SIGNAL( send_command( player*, std::string ) ), game::get_instance(), SLOT( command_received( player*, std::string ) ) );
};


player* algorithm::get_owner()
{
	return owner;
};


void algorithm::set_owner(player* p)
{
	owner = p;
};


void algorithm::next_command()
{
	emit send_command( owner, commands.front() );
	commands.pop_front();
};



ai_algorithms::ai_algorithms( int _x ): x( _x )
{
	algorithm* al;

	al = new search_algorithm();
	algorithm_list[ al->get_name() ] = al;

	al = new reflex_algorithm();
	algorithm_list[ al->get_name() ] = al;
};



ai_algorithms* ai_algorithms::get_instance()
{
	static ai_algorithms inst(0);
	return &inst;
};